package org.x.note.socket;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.nio.charset.Charset;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * [文件名称]<br>
 * SocketUtils <br>
 * <br>
 * [文件描述]<br>
 * Socket工具类<br>
 * 需要注入socket对象来使用，默认以报文前4位为长度为标准<br>
 * [修改记录]<br>
 * 2012-5-1 ver1.00 创建 xyl<br>
 * 
 * @author xyl
 * @version 1.00
 */
public class SocketUtil {

	/**
	 * log
	 */
	private static final Logger		logger	= LoggerFactory
													.getLogger(SocketUtil.class);

	/**
	 * socket
	 */
	private Socket					socket	= null;

	/**
	 * 输入流
	 */
	private BufferedInputStream		inputStream;

	/**
	 * 输出流
	 */
	private BufferedOutputStream	outputStream;

	/**
	 * 编码，默认为UTF-8
	 */
	private Charset					charset	= Charset.forName("UTF-8");

	/**
	 * 报文长度的位数
	 */
	private int						count	= 4;

	/**
	 * 构造器
	 * 
	 * @param socket
	 *            套接字
	 * @param charsetName
	 *            编码
	 * @throws IOException
	 */
	public SocketUtil(Socket socket) throws IOException {
		this.socket = socket;
		this.outputStream = new BufferedOutputStream(socket.getOutputStream());
		this.inputStream = new BufferedInputStream(socket.getInputStream());
	}

	/**
	 * 构造器
	 * 
	 * @param socket
	 *            套接字
	 * @param charsetName
	 *            编码
	 * @throws IOException
	 */
	public SocketUtil(Socket socket, String charsetName) throws IOException {
		this.socket = socket;
		this.outputStream = new BufferedOutputStream(socket.getOutputStream());
		this.inputStream = new BufferedInputStream(socket.getInputStream());
		this.charset = Charset.forName(charsetName);
	}

	/**
	 * 构造器
	 * 
	 * @param socket
	 *            套接字
	 * @param charsetName
	 *            编码
	 * @param count
	 *            报文长度的位数
	 * @throws IOException
	 */
	public SocketUtil(Socket socket, String charsetName, int count)
			throws IOException {
		this.socket = socket;
		this.outputStream = new BufferedOutputStream(socket.getOutputStream());
		this.inputStream = new BufferedInputStream(socket.getInputStream());
		this.charset = Charset.forName(charsetName);
		this.count = count;
	}

	/**
	 * 获取当前socket
	 * 
	 * @return socket
	 */
	public Socket getSocket() {
		return socket;
	}

	/**
	 * 发送报文，默认有长度位
	 * 
	 * @param message
	 *            报文
	 * @throws IOException
	 */
	public void sendMessage(String message) throws IOException {
		sendMessage(message, true);
	}

	/**
	 * 发送报文
	 * 
	 * @param message
	 *            报文
	 * @param hasLength
	 *            是否有报文长度位，true/false：有/没有
	 * @throws IOException
	 */
	public void sendMessage(String message, boolean hasLength)
			throws IOException {
		// 获取报文长度
		int length = message.getBytes(charset).length;
		logger.debug("发送报文的长度[{}]", length);

		StringBuffer temp = new StringBuffer(length + 6);
		if (hasLength) {
			temp.append(StringUtils.leftPad("" + length, 4, "0"));
		}
		temp.append(message);
		temp.append("\r\n");

		outputStream.write(temp.toString().getBytes(charset));
		outputStream.flush();

		logger.debug("发送报文[{}]", message);
	}

	/**
	 * 获取报文长度
	 * 
	 * @param count
	 *            报文前count位表示整条报文的长度
	 * @return 报文长度
	 * @throws IOException
	 */
	private int getMessageLength(int count) throws IOException {
		byte[] bt = new byte[count];
		inputStream.read(bt, 0, count);
		int length = NumberUtils.toInt(new String(bt, charset), 0);
		logger.debug("接收报文的长度[{}]", length);
		return length;
	}

	/**
	 * 以报文长度来接收报文byte
	 * 
	 * @return 报文的byte[]
	 * @throws IOException
	 */
	public byte[] receiveBytesByLength() throws IOException {
		int length = getMessageLength(count);
		byte[] receiveBytes = new byte[length];
		inputStream.read(receiveBytes, 0, length);
		return receiveBytes;
	}

	/**
	 * 以报文长度来接收报文
	 * 
	 * @return 报文
	 * @throws IOException
	 */
	public String receiveMessageByLength() throws IOException {
		String message = new String(receiveBytesByLength(), charset);
		logger.debug("接收报文[{}]", message);
		return message;
	}

	/**
	 * 无报文长度位时接受报文
	 * 
	 * @return
	 * @throws IOException
	 */
	public String receiveMessage() throws IOException {
		byte[] buffer = new byte[2048];
		int count = inputStream.read(buffer);

		byte[] receiveBytes = new byte[count];
		System.arraycopy(buffer, 0, receiveBytes, 0, count);

		String message = new String(receiveBytes, charset);

		logger.debug("接收报文[{}]", message);
		return message;
	}

	/**
	 * 关闭socket
	 * 
	 * @throws IOException
	 */
	public void closeSocket() {
		try {
			outputStream.close();
			inputStream.close();
			socket.close();
		} catch (IOException e) {
			logger.warn("socket关闭异常", e);
		}
	}
}
